using System;
using System.IO;
using System.Linq;
using BSDS.Core.Data.Local;
using BSDS.Core.Data.TemporaryFiles;
using BSDS.Core.Infrastructure.Logging;
using BSDS.Core.Model.Data;

namespace BSDS.Core.Model.Services
{
    public class DataRepository
    {
        private readonly LocalDataParserFactory parserFactory;
        private readonly LocalDataSerializerFactory serializerFactory;
        private readonly FilenameProvider filenameProvider;
        private readonly Logger logger;

        internal DataRepository(LocalDataParserFactory parserFactory, LocalDataSerializerFactory serializerFactory,
            FilenameProvider filenameProvider, Logger logger)
        {
            this.parserFactory = parserFactory;
            this.serializerFactory = serializerFactory;
            this.filenameProvider = filenameProvider;
            this.logger = logger;
        }

        public BsdsData LoadFromFile(string filename)
        {
            var parser = parserFactory.Create(filename);

            try
            {
                return parser.Parse(filename);
            }
            catch(Exception e)
            {
                logger.Log("Error parsing file " + filename + ":" + e.Message);

                throw new FileLoadException("Invalid file format.", e);
            }
        }

        public void SaveToFile(BsdsData bsdsData, string filename, DataFormat format)
        {
            SaveToFile(bsdsData.Entities, filename, format, bsdsData.EntityTypeName);
        }

        public void SaveToFile(BsdsData bsdsData, string filename)
        {
            var serializer = serializerFactory.Create(bsdsData.OriginalFormat);

            serializer.Serialize(bsdsData.Entities, bsdsData.EntityTypeName, filename);
        }

        public void SaveToFile(EntityValue[] entities, string filename, DataFormat format, string entityTypeName)
        {
            var serializer = serializerFactory.Create(format);

            serializer.Serialize(entities, entityTypeName, filename);
        }

        public string SaveForUpload(EntityValue[] entities, DataFormat format, string entityTypeName, string prefix)
        {
            var filename = filenameProvider.New(prefix);

            var serializer = serializerFactory.Create(format);

            serializer.Serialize(entities, entityTypeName, filename, SerializationOptions.SerializeForUpload);
            
            return filename;
        }

        public bool CanBeSaved(BsdsData data, DataFormat format)
        {
            if (format == DataFormat.Pipe)
            {
                return data.Entities.SelectMany(entity => entity.AttributeValues)
                                    .All(attribute => !attribute.Value.Contains("|"));
            }

            return true;
        }

        public void SaveInPortalFormat(BsdsData data, string filename, DataFormat format)
        {
            if (format != DataFormat.Tab && format != DataFormat.Pipe)
            {
                throw new Exception("/portal options is valid only for /format=tab or /format=pipe");
            }

            var serializer = serializerFactory.Create(format);

            serializer.Serialize(data.Entities, data.EntityTypeName, filename,
                SerializationOptions.SerializeToPortal);
        }
    }
}
